# -*- coding: utf-8 -*-

"""
@author: Laowang
@contact: QQ:1125564921
@Created on: 2022/6/21
@Remark: 
"""

import time
import hmac
import requests
import hashlib
import json
import base64
import urllib.parse
from functools import wraps
from typing import Dict
from collections import OrderedDict
from urllib.parse import urlparse

from framework_strategy.gopy.gateways.settings import XTAPISETTING, XT4APISETTING
from framework_strategy.gopy.gateways.utils import RequestParamterObj, request, ResponseEventObj


class Auth:
    """Create auth signed  """

    def __new__(cls, *args, **kwargs):
        if not hasattr(Auth, "_instance"):
            Auth._instance = object.__new__(cls)
        return Auth._instance

    def __init__(self, apiKey, secretKey):
        self._apiKey: str = apiKey
        self._secretKey: str = secretKey

    def create_header(self):

        header = OrderedDict()
        header["xt-validate-timestamp"] = str(int(time.time() * 1000))
        header["xt-validate-appkey"] = self._apiKey
        # header["xt-validate-algorithms"] = "HmacSHA256"
        return header

    def create_payload(self, payload: dict, uri) -> dict:

        # Need sorted
        header = self.create_header()
        X = urllib.parse.urlencode(
            dict(sorted(header.items(), key=lambda kv: (kv[0], kv[1]))))
        path = urlparse(uri).path
        decode, tmp = "application/json;charset=UTF-8", None

        if payload.pop("urlencoded", False):
            tmp = urllib.parse.urlencode(
            dict(sorted(payload.items(), key=lambda kv: (kv[0], kv[1]))))
            decode = "application/x-www-form-urlencoded"

        if not payload:
            param = None
            Y = "#{}".format(path)
        else:
            param = json.dumps(payload)
            Y = "#{}#{}".format(path, tmp or param)
            param = payload

        signature = self._create_signed(X + Y)
        header["xt-validate-signature"] = signature
        header["Content-Type"] = decode

        print("[xt] :::", X + Y)
        return header, param

    def _create_signed(self, params: str) -> str:
        signature = hmac.new(self._secretKey.encode(
            'utf-8'), params.encode('utf-8'), hashlib.sha256).hexdigest().upper()
        return signature


def get_auth_payload(param: dict, uri) -> dict:
    """ return payload contains request params"""
    PUBLIC_KEY = param.pop("accesskey") or XT4APISETTING.PUBLIC_KEY
    SECRET_KEY = param.pop("secretkey") or XT4APISETTING.SECRET_KEY
    auth = Auth(PUBLIC_KEY, SECRET_KEY)
    return auth.create_payload(param, uri)


# Need auth
# You can do request statistics here,
# as well as response results record
# or do stream limiting here etc
def auth_require_(this, event, parameter: RequestParamterObj):

    _, event_data = parameter.data, parameter.data.event_data
    headers, params = get_auth_payload(event_data.kwargs, parameter.uri)

    try:
        res = request(
            parameter.method,
            parameter.uri,
            # params,
            None,
            this.proxy,
            headers=headers,
            exchange=event_data.exchange,
            json=params,
            pop_header_body=True,
        )
    except (requests.exceptions.HTTPError, requests.exceptions.ConnectTimeout) as err:  # NOQA
        res = False, {}, None

    res = ResponseEventObj(*res, event)
    return res


# Public
# You can do request statistics here,
# as well as response results record
# or do stream limiting here etc
def public_request_(this, event, parameter: RequestParamterObj):

    _, event_data = parameter.data, parameter.data.event_data
    params = event_data.kwargs
    headers = {"Content-Type":"application/x-www-form-urlencoded"}
    try:
        res = request(parameter.method, parameter.uri, params,
                      this.proxy, exchange=event_data.exchange,
                      headers=headers)
    except (requests.exceptions.HTTPError, requests.exceptions.ConnectTimeout) as err:  # NOQA
        res = False, {}, None
    res = ResponseEventObj(*res, event)
    return res

